import hashlib
import random
import string
import time

import xmltodict
from django.conf import settings
from django.core.files.base import ContentFile
from django.db import transaction
from rest_framework.response import Response
from rest_framework_jwt.settings import api_settings

import base64
import json
import requests
import logging

logger = logging.getLogger("django")
from Crypto.Cipher import AES

"""
请求注册登陆
1、前端传送数据 获取code ,encryptedData,iv
2、请求session_key
3、解密encryptedData
4、保存用户


"""
from applet.models import *
from users.models import *


class WXBizDataCrypt:
    def __init__(self, appId, sessionKey=None):
        self.appId = appId
        self.sessionKey = sessionKey

    def decrypt(self, encryptedData, iv):
        # base64 decode
        sessionKey = base64.b64decode(self.sessionKey)
        encryptedData = base64.b64decode(encryptedData)
        iv = base64.b64decode(iv)

        cipher = AES.new(sessionKey, AES.MODE_CBC, iv)

        decrypted = json.loads(self._unpad(cipher.decrypt(encryptedData)).decode())

        if decrypted['watermark']['appid'] != self.appId:
            raise Exception('Invalid Buffer')
        # 获得解密用户信息
        return decrypted

    def _unpad(self, s):
        return s[:-ord(s[len(s) - 1:])]

    def create_token(self, encryptedData, iv):
        # 使用unionid查询该微信用户是否在项目中绑定过用户

        try:
            user_dict_data = self.decrypt(encryptedData, iv)
        except Exception as e:
            logger.error(e)
            return ""
        try:
            oauth_user = OAuthUser.objects.get(weixin_unionid=user_dict_data['unionid'])
            oauth_user.applet_openid = user_dict_data["openid"]
            oauth_user.save()
        except OAuthUser.DoesNotExist:
            # 如果weixin_unionid没绑定用户，创建用户并绑定到weixin_unionid
            # 创建新用户，保存到数据库
            user = User.objects.create_user(
                username=user_dict_data['unionid'],
                nickname=user_dict_data['nickname'],
                gender='male' if user_dict_data['sex'] == 1 else 'female',
            )
            # 发送请求，获取微信头像数据
            try:
                res = requests.get(user_dict_data['avatarUrl'])
            except Exception as e:
                logger.error('请求获取微信头像[异常][errmsg: %s, headimgurl: %s]' % (e, user_dict_data['avatarUrl']))
            else:
                data = res.content
                # 获取django.core.files.File的一个实例
                file_content = ContentFile(data)
                # 保存的文件名
                file_name = datetime.now().strftime("%Y%m%d_%H%M%S%f") + '.jpg'
                # 获取上传头像的FieldFile实例
                avatar = user.user_avatar
                # 保存图片到本地和保存路径到数据库
                avatar.save(file_name, file_content)
            # 将用户绑定微信unionid
            OAuthUser.objects.create(
                weixin_unionid=user_dict_data['unionid'],
                applet_openid=user_dict_data['openid'],
                user=user
            )
            # 生成JWT token，并响应
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)

            response = {
                'token': token,
                'user_id': user.id,
                'nickname': user.nickname,
                'user_avatar': "http://www.xpillars.com/media/" + str(user.user_avatar)
            }

            return response
        else:
            # 如果weixin_unionid已绑定用户，直接生成JWT token，并返回
            jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
            jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER

            # 获取oauth_user关联的user
            user = oauth_user.user
            if user.nickname != user_dict_data['nickname']:
                # 更新新的名字
                user.nickname = user_dict_data['nickname']
                user.save()
                # print(user.username, '修改名字成功')
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)

            response ={
                'token': token,
                'user_id': user.id,
                'nickname': user.nickname,
                'user_avatar': "https://www.xpillars.com/media/" + str(user.user_avatar)
            }
            # end = time.time()
            # print('wxlog/接口执行时间', end - start)
            # print(str(user.user_avatar))
            return response

    @staticmethod
    def get_sessionkey(code):
        openid_url = "https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code" % (
            settings.APPLET_APPID, settings.APPLET_SECRET, code
        )
        req = requests.get(openid_url)
        rep = req.json()
        errcode = rep.get("errcode")
        if errcode == 0:
            session_key = rep.get("session_key")
            return session_key
        else:
            errcode = rep.get("errcode")
            errmsg = rep.get("errmsg")
            logger.error("小程序获取session_key失败，错误代码[err_code][%s]错误信息[err_code_des][%s]" % (errcode, errmsg))
            return ""



def AppletPayment(user, orderid, goodsPrice, goosName):
    """

    :param user: 用户对象，查询关联的openid
    :param orderid: 商户订单号
    :param goodsPrice: 支付价格
    :param goosName: 商品名字
    :return:
    """
    params = dict()
    url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
    appid = settings.APPLET_APPID
    mch_id = settings.MCG_ID
    key = settings.MCH_ID_KEY
    nonce_str = str(int(round(time.time() * 1000))) + ("%03d" % (random.randint(0, 999))) + "".join(
        random.sample(string.ascii_lowercase, 5)).replace(" ", "")  # 生成随机字符串
    spbill_create_ip = "127.0.0.1"
    notifyurl = settings.NOTIFYURL
    oauth_user = user.oauthuser_set.first()
    params["openid"] = oauth_user.applet_openid
    params["appid"] = appid
    # print(params["appid"])
    params["mch_id"] = mch_id
    params["nonce_str"] = nonce_str
    params["out_trade_no"] = orderid
    # 客户端生成并传过来，参数必须用utf8编码，否则报错
    params["total_fee"] = goodsPrice  # 单位是分，必须是整数
    params['spbill_create_ip'] = spbill_create_ip
    params["notify_url"] = notifyurl
    params["body"] = goosName
    params["trade_type"] = "JSAPI"

    ret = []
    for k in sorted(params.keys()):
        if (k != "sign") and (k != "") and (params[k] is not None):
            ret.append("%s=%s" % (k, params[k]))
    # print(ret)
    params_str = "&".join(ret)
    # print("&", params_str)
    params_str = "%(params_str)s&key=%(partner_key)s" % {"params_str": params_str, "partner_key": key}
    # print(params_str, "aaaa")
    # importlib.reload(sys)
    params_str = hashlib.md5(params_str.encode("utf-8")).hexdigest()
    sign = params_str.upper()
    params["sign"] = sign

    xml_dict = {
        "xml": params
    }
    request_xml_str = xmltodict.unparse(xml_dict)
    xml_str = requests.post(url=url,
                            data=request_xml_str.encode('utf-8')).content
    doc = xmltodict.parse(xml_str)

    if doc["xml"]["return_code"] == "SUCCESS":
        if doc["xml"]["result_code"] == "SUCCESS":
            data = dict()
            data["appId"] = doc["xml"]["appid"]
            data["timeStamp"] = str(time.time()).split('.')[0]
            data["nonceStr"] = doc["xml"]["nonce_str"]
            data["package"] = doc["xml"]["prepay_id"]
            data["signType"] = doc["xml"]["sign"]
            return data
        else:
            err_code = doc["xml"]["err_code"]
            err_code_des = doc["xml"]["err_code_des"]
            logger.error("小程序支付失败，错误代码[err_code][%s]错误代码描述[err_code_des][%s]" % (err_code, err_code_des))
            return ""
    else:
        return_msg = doc["xml"]["return_msg"]
        logger.error("小程序支付失败错误原因·[return_msg][%s]" % return_msg)
        return ""
class appletpayStatus(object):

    def __init__(self, body):
        self.body = body

    def order_result_xml(self):
        # print("微信回调")
        # order_result_xml = request.body.decode("utf-8")
        doc = xmltodict.parse(self.body)  # 解析得到的xml字符串，转为dict

        return doc


    def verify_doc(self):
        doc = self.order_result_xml()
        out_trade_no = doc['xml']['out_trade_no']  # 提取返回数据中的订单号
        transaction_id = doc["xml"]["transaction_id"]  # 微信订单号
        total_amount = doc["xml"]["total_fee"]  # 支付的订单金额
        wei_sign = doc["xml"]["sign"]  # 提取签名
        result_code = doc["xml"]["result_code"]
        # print(result_code, """result_code""")
        # print(out_trade_no, transaction_id, total_amount, wei_sign, type(total_amount))
        total = int(total_amount) / 100
        # todo：提取签名、支付金额等，验证签名是否正确、金额是否正确
        # transaction_id_str = OrderInfo.objects.filter(trade_no=transaction_id)
        # if transaction_id_str:
        #     xml_data = "<xml>" \
        #                "<return_code><![CDATA[SUCCESS]]></return_code>" \
        #                "<return_msg><![CDATA[OK]]></return_msg>" \
        #                "</xml>"
        #     return xml_data
        #
        # with transaction.atomic():
        #     save_id = transaction.savepoint()
        #     try:
        #     订单处理业务逻辑
        #     except Exception as e:
        #         logger.error("小程序订单保存失败[%s]" % e)
        #         transaction.savepoint_rollback(save_id)
        #         return ""
        #     transaction.savepoint_commit(save_id)
        xml_data = "<xml>" \
                   "<return_code><![CDATA[SUCCESS]]></return_code>" \
                   "<return_msg><![CDATA[OK]]></return_msg></xml>"
        return xml_data
